package org.lemon.cla.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
// IMPORTANT: Make sure this is the OpenAPI Parameter
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn; // For Parameter.In.QUERY/PATH etc.
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.lemon.cla.enums.*;
import org.lemon.cla.dto.response.ResponseResult;
import org.lemon.cla.dto.request.ClubApplicationCreateRequest;
import org.lemon.cla.dto.request.ClubApplicationUpdateRequest;
import org.lemon.cla.dto.request.ClubApplicationSearchRequest;
import org.lemon.cla.exception.*;
import org.lemon.cla.pojo.ClubApplication;
import org.lemon.cla.pojo.ClubMember;
import org.lemon.cla.pojo.User;
import org.lemon.cla.pojo.Club;
import org.lemon.cla.service.IClubMemberService;
import org.lemon.cla.vo.ClubApplicationVo;
import org.lemon.cla.service.IClubApplicationService;
import org.lemon.cla.service.IUserService;
import org.lemon.cla.service.IClubService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; // Spring Web Annotations
import jakarta.validation.Valid;

import java.time.LocalDateTime;
import java.util.Optional;


@RestController
@RequestMapping("/api/club-applications")
@Tag(name = "社团申请管理", description = "提供社团申请信息的 CRUD 和审核接口")
public class ClubApplicationController {

    @Autowired
    private IClubApplicationService clubApplicationService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IClubService clubService;
    @Autowired
    private IClubMemberService clubMemberService;

    @Operation(summary = "获取所有社团申请", description = "分页获取所有社团申请列表，**包含申请人和审核人信息 (若用户被逻辑删除则显示为未知)**")
    @GetMapping
    public ResponseResult<IPage<ClubApplicationVo>> getAllClubApplications(
            @Parameter(description = "页码", example = "1", in = ParameterIn.QUERY) @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10", in = ParameterIn.QUERY) @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<ClubApplicationVo> page = new Page<>(pageNum, pageSize);
        IPage<ClubApplicationVo> applicationPage = clubApplicationService.getAllClubApplicationsVo(page);
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), applicationPage);
    }

    @Operation(summary = "根据ID获取社团申请", description = "根据申请ID获取社团申请详情，**包含申请人和审核人信息 (若用户被逻辑删除则显示为未知)**")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取申请"),
            @ApiResponse(responseCode = "404", description = "申请未找到")
    })
    @GetMapping("/{id}")
    public ResponseResult<ClubApplicationVo> getClubApplicationById(
            @Parameter(description = "申请ID", required = true, example = "1", in = ParameterIn.PATH) @PathVariable Long id) {
        return Optional.ofNullable(clubApplicationService.getClubApplicationVoById(id))
                .map(applicationVo -> ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), applicationVo))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请未找到。"));
    }

    @Operation(summary = "创建新社团申请", description = "创建一个新的社团申请记录 (**申请人不能是逻辑删除状态**，自动设置申请时间、初始状态为待审核)")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "申请创建成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误 (如校验失败)"),
            @ApiResponse(responseCode = "404", description = "申请社团或申请人用户不存在或已逻辑删除"),
            @ApiResponse(responseCode = "409", description = "该用户已有待审核的社团申请")
    })
    @PostMapping
    @PreAuthorize("isAuthenticated()")
    public ResponseResult<ClubApplication> createClubApplication(
            @Parameter(description = "社团申请创建请求对象 (无需传入 applicationId, applicationTime, status, reviewTime, reviewerId)", required = true)
            @RequestBody @Valid ClubApplicationCreateRequest request) {

        // 1. 业务校验：申请人用户是否存在且未被逻辑删除
        Optional.ofNullable(userService.getById(request.getUserId().intValue()))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请创建失败：申请人用户不存在或已逻辑删除。"));

        // 2. 业务校验：申请社团是否存在且未被逻辑删除
        Optional.ofNullable(clubService.getById(request.getClubId()))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请创建失败：申请社团不存在或已逻辑删除。"));

        // 3. 业务校验：检查该用户是否已有该社团的待审核申请
        if (clubApplicationService.hasPendingApplication(request.getUserId(), request.getClubId())) {
            throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(), "该用户已对该社团提交了待审核的申请，请勿重复申请。");
        }

        ClubApplication clubApplication = new ClubApplication();
        BeanUtils.copyProperties(request, clubApplication);

        clubApplication.setApplicationTime(LocalDateTime.now());
        clubApplication.setStatus(ClubApplicationStatusEnum.PENDING_REVIEW);

        boolean success = clubApplicationService.save(clubApplication);
        if (!success) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "社团申请创建失败，请稍后重试。");
        }
        return ResponseResult.success(HttpStatusEnum.CREATED.getCode(), HttpStatusEnum.CREATED.getMessage(), clubApplication);
    }

    @Operation(summary = "更新社团申请信息", description = "根据申请ID更新社团申请信息（不包括状态和审核人信息，这些应通过审核接口处理）")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "申请更新成功"),
            @ApiResponse(responseCode = "400", description = "请求参数错误"),
            @ApiResponse(responseCode = "404", description = "申请未找到")
    })
    @PutMapping("/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<ClubApplication> updateClubApplication(
            @Parameter(description = "申请ID", required = true, example = "1", in = ParameterIn.PATH) @PathVariable Long id,
            @Parameter(description = "更新后的社团申请对象", required = true) @RequestBody @Valid ClubApplicationUpdateRequest request) {

        ClubApplication existingApplication = Optional.ofNullable(clubApplicationService.getById(id))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请未找到。"));

        existingApplication.setReason(request.getReason());

        boolean success = clubApplicationService.updateById(existingApplication);
        if (!success) {
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "社团申请更新失败，请稍后重试。");
        }
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), existingApplication);
    }

    @Operation(summary = "删除社团申请", description = "根据申请ID删除社团申请")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "申请删除成功"),
            @ApiResponse(responseCode = "404", description = "申请未找到")
    })
    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> deleteClubApplication(
            @Parameter(description = "申请ID", required = true, example = "1", in = ParameterIn.PATH) @PathVariable Long id) {
        boolean success = clubApplicationService.removeById(id);
        if (!success) {
            throw new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请未找到或删除失败。");
        }
        return ResponseResult.success(HttpStatusEnum.NO_CONTENT.getCode(), HttpStatusEnum.NO_CONTENT.getMessage(), null);
    }

    @Operation(summary = "模糊查询社团申请(查询首选)", description = "根据用户ID、社团ID、理由、状态、时间范围、审核人ID进行模糊查询，**返回包含申请人和审核人信息的视图对象 (若用户被逻辑删除则显示为未知)**")
    @PostMapping("/search")
    public ResponseResult<IPage<ClubApplicationVo>> searchClubApplications(
            @Parameter(description = "页码", example = "1", in = ParameterIn.QUERY) @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页数量", example = "10", in = ParameterIn.QUERY) @RequestParam(defaultValue = "10") Integer pageSize,
            @Parameter(description = "社团申请查询请求对象", required = true) @RequestBody ClubApplicationSearchRequest request) {

        Page<ClubApplicationVo> page = new Page<>(pageNum, pageSize);
        IPage<ClubApplicationVo> resultPage = clubApplicationService.searchClubApplicationsByConditions(page, request);
        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), resultPage);
    }



    @Operation(
            summary = "审核社团申请",
            description = "根据申请ID审核社团申请，设置其状态、审核人、审核时间和回复。**如果申请状态变更为 '已批准'，系统将自动为申请人添加一条新的社团成员记录。**"
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "社团申请审核成功。如果状态为 '已批准'，则社团成员已成功添加。"
            ),
            @ApiResponse(
                    responseCode = "400",
                    description = "请求参数校验失败，例如：\n" +
                            "- 无效的申请状态值 (如传入了不在枚举范围内的状态)。\n" +
                            "- 审核通过时，申请人用户或关联社团已被逻辑删除 (此时会抛出 BadRequestException)。"
            ),
            @ApiResponse(
                    responseCode = "404",
                    description = "资源未找到，例如：\n" +
                            "- 指定的社团申请记录不存在。\n" +
                            "- 审核人用户不存在或已被逻辑删除。"
            ),
            @ApiResponse(
                    responseCode = "409",
                    description = "业务冲突，例如：\n" +
                            "- 该用户已对该社团提交了待审核的申请 (理论上审核接口不会直接触发此情况，但考虑到整体业务流程预防性描述)。\n" +
                            "- 审核通过时，该用户已是目标社团的成员，无法重复添加。"
            ),
            @ApiResponse(
                    responseCode = "500",
                    description = "服务器内部错误，操作失败，例如：\n" +
                            "- 数据库操作失败。\n" +
                            "- 审核操作本身未能成功更新申请状态。\n" +
                            "- 审核通过后，在尝试创建社团成员记录时发生意外错误。"
            )
    })
    @PutMapping("/{id}/review")
    @PreAuthorize("hasRole('管理员')")
    public ResponseResult<Void> reviewClubApplication(
            @Parameter(description = "要审核的社团申请的唯一标识符。", required = true, example = "1", in = ParameterIn.PATH)
            @PathVariable Long id,
            // Corrected: Spring's @RequestParam for query params, OpenAPI's @Parameter with in=QUERY
            @Parameter(description = "社团申请人的用户ID。", required = true, example = "1", in = ParameterIn.QUERY)
            @RequestParam Long applicateUserId,
            // Corrected: Spring's @RequestParam for query params, OpenAPI's @Parameter with in=QUERY
            @Parameter(description = "社团ID，表示申请加入的社团。", required = true, example = "1", in = ParameterIn.QUERY)
            @RequestParam Long clubId,
            @Parameter(description = "新的申请状态。接受的值包括 '待审核', '已批准', '已拒绝', '已取消'。", required = true, example = "已批准", schema = @Schema(implementation = ClubApplicationStatusEnum.class), in = ParameterIn.QUERY)
            @RequestParam String status,
            @Parameter(description = "执行审核操作的管理员用户ID。", required = true, example = "101", in = ParameterIn.QUERY)
            @RequestParam Long reviewerId) {

        // 1. 校验审核人是否存在且未被逻辑删除
        Optional.ofNullable(userService.getById(reviewerId.intValue()))
                .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "审核失败：审核人用户不存在或已逻辑删除。"));

        // 2. 转换状态字符串为枚举
        ClubApplicationStatusEnum newStatus = ClubApplicationStatusEnum.fromDescription(status);
        // IllegalArgumentException thrown by fromDescription() will be caught by GlobalExceptionHandler

        // 3. 调用 Service 层进行审核逻辑处理
        boolean success = clubApplicationService.reviewClubApplication(id, newStatus, reviewerId);
        if (!success) {
            // If Service returns false, it could be due to the application not existing or an update failure
            Optional.ofNullable(clubApplicationService.getById(id))
                    .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "社团申请未找到。"));
            throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "社团申请审核失败，请稍后重试。");
        }

        // 4. 如果审核通过，插入社团成员记录
        Optional.of(newStatus)
                .filter(ClubApplicationStatusEnum.APPROVED::equals)
                .ifPresent(s -> {
                    // 4.1 再次校验申请人是否存在且未被逻辑删除
                    Optional.ofNullable(userService.getById(applicateUserId.intValue()))
                            .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "审核通过失败：申请人用户不存在或已逻辑删除。"));

                    // 4.2 校验社团是否存在且未被逻辑删除
                    Optional.ofNullable(clubService.getById(clubId))
                            .orElseThrow(() -> new BusinessException(HttpStatusEnum.NOT_FOUND.getCode(), "审核通过失败：关联社团不存在或已逻辑删除。"));

                    // 4.3 检查用户是否已是该社团成员（避免重复添加，针对联合唯一约束）
                    if (clubMemberService.isMemberExists(applicateUserId, clubId)) {
                        throw new BusinessException(HttpStatusEnum.CONFLICT.getCode(),"审核通过失败：该用户已是该社团成员。");
                    }

                    // 4.4 创建并保存社团成员记录
                    ClubMember newClubMember = new ClubMember();
                    newClubMember.setUserId(applicateUserId);
                    newClubMember.setClubId(clubId); // Corrected: Should be clubId, not applicateUserId
                    newClubMember.setJoinTime(LocalDateTime.now());
                    newClubMember.setRole(ClubMemberRoleEnum.MEMBER);
                    newClubMember.setStatus(ClubMemberStatusEnum.JOINED);

                    boolean memberSaveSuccess = clubMemberService.save(newClubMember);
                    if (!memberSaveSuccess) {
                        throw new BusinessException(HttpStatusEnum.BAD_REQUEST.getCode(), "审核通过后创建社团成员记录失败，请稍后重试。");
                    }
                });

        return ResponseResult.success(HttpStatusEnum.SUCCESS.getCode(), "社团申请审核成功", null);
    }
}